package com.example.demo.domain.application;

import com.example.demo.domain.application.repository.ApplicationRepository;
import com.example.demo.domain.application.repository.UserOpenRepository;
import com.example.demo.domain.category.CategoryApplicationSortService;
import com.example.demo.domain.platform.PlatformRelease;
import com.example.demo.domain.platform.PlatformService;
import com.example.demo.domain.user.User;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

/**
 * 应用
 *
 * @author yingjianhua
 */
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
@Configuration
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "scale")
public class Application {

    protected static ApplicationRepository repository;

    protected static UserOpenRepository openRepository;

    protected static PlatformService platformService;

    protected static CategoryApplicationSortService sortService;

    @Autowired
    private void setApplicationRepository(ApplicationRepository repository) {
        Application.repository = repository;
    }

    @Autowired
    private void setApplicationUserOpenRepository(UserOpenRepository openRepository) {
        Application.openRepository = openRepository;
    }

    @Autowired
    private void setPlatformService(PlatformService platformService) {
        Application.platformService = platformService;
    }

    @Autowired
    private void setCategoryApplicationSortService(CategoryApplicationSortService sortService) {
        Application.sortService = sortService;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    /**
     * code 需要全局唯一
     */
    private String code;
    /**
     * 应用名称
     */
    private String name;
    /**
     * 应用图标
     */
    private String icon;
    /**
     * 付费类型
     * 暂时 0: 免费， 1: 收费
     */
    private Byte paymentModel = 0;

    protected Application(String name, String icon) {
        this.setCode(generateAppCode());
        this.setName(name);
        this.setIcon(icon);
    }

    /**
     * 应用的规模
     */
    @Enumerated(EnumType.STRING)
    @Column(insertable = false, updatable = false)
    private ApplicationScale scale;

    public void setName(@NotNull @NotBlank(message = "应用名不能为空") @Size(max = 10, message = "应用名最多可输入10字") String name) {
        if (name.equals(this.name)) {
            return;
        }

        if (Application.repository.findByName(name).isPresent()) {
            throw new RuntimeException("应用名称已经被使用");
        }
        this.name = name;
    }

    public void setPaymentModel(Byte paymentModel) {
        // 现在还不提供修改, TODO
    }

    /**
     * 用户必须已经开通了该应用，否则抛出异常
     *
     * @param user 用户
     */
    protected void mustOpen(User user) {
        if (!isOpen(user)) {
            throw new RuntimeException("你还没有开通呢");
        }
    }

    /**
     * 用户必须还未开通该应用，否则抛出异常
     *
     * @param user 用户
     */
    protected void mustClose(User user) {
        if (isOpen(user)) {
            throw new RuntimeException("已经开通了哦");
        }
    }

    /**
     * 当前操作员是否有权限对用户进行开通和关闭应用的操作
     *
     * @param operator 操作员
     * @param user     用户
     * @return 是否有权限
     */
    protected boolean havePermission(User operator, User user) {
        return true;
    }

    /**
     * 应用开通的权限约束， 当前操作员是否有对某个用户变更开通状态的权限
     * @param operator 操作员
     * @param user 用户
     */
    protected void permissionConstrain(User operator, User user) {
        if (!havePermission(operator, user)) {
            throw new RuntimeException("没有权限哦");
        }
    }

    /**
     * 应用开通的约束判断，当前应用的状态是否满足开通的要求
     */
    public void openConstrain() {
        // 开通之前需要判断， 该应用是否已经在某个平台发布了
        // 假如在其中一个平台发布过了，就可以开通啦。
        boolean anyReleased = platformService.getReleaseInfo(this).stream().anyMatch(PlatformRelease::getReleased);
        if (!anyReleased) {
            throw new RuntimeException("请至少在一个平台上发布");
        }
    }

    /**
     * 用户是否已经开通该应用
     *
     * @param user 用户
     * @return 是否已经开通
     */
    public boolean isOpen(User user) {
        return openRepository.findByApplicationAndUser(this, user).isPresent();
    }

    /**
     * 生成code
     *
     * @return code
     */
    private static String generateAppCode() {
        return "DJ" + (int) ((Math.random() * 9 + 1) * 10000000);
    }

    @Override
    public String toString() {
        return "Application{" +
                "id=" + id +
                ", code='" + code + '\'' +
                ", name='" + name + '\'' +
                ", icon='" + icon + '\'' +
                ", paymentModel=" + paymentModel +
                ", scale=" + scale +
                '}';
    }
}
